/*
MIT License 

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов, 

https://bmstu.codes/lsx/simodo
*/

#ifndef simodo_token_Reporter_abstract
#define simodo_token_Reporter_abstract

/*! \file Reporter_abstract.h
    \brief Интерфейс к выводу сообщений из библиотеки во внешнюю программу
*/

#include "simodo/inout/token/Location.h"

namespace simodo::inout
{
    //! Степень суровости ошибки
    enum class SeverityLevel
    {
        Information = 0, ///< Информационное сообщение
        Warning,         ///< Предупреждение: возможна некорректная работа
        Error,           ///< Ошибка: работа не выполнена, причина понятна и может быть описана
        Fatal,           ///< Сбой: работа не выполнена, причина не понятна
    };

    /*!
     * \brief Абстрактный класс, выполняющий передачу сообщений
     *
     *      Определяет интерфейс передачи сообщений из библиотеки. 
     *      Предполагается, что способ отображение сообщений будет реализовано в классах-наследниках.
     */
    class Reporter_abstract
    {
    public:
        virtual ~Reporter_abstract() = default; ///< Виртуальный деструктор
  
        /*!
         * \brief Пустой (интерфейсный) метод передачи сообщения
         *
         *      Метод может передавать информацию о локализации сообщения.
         *
         *      Данный метод является единственным интерфейсным методом.
         *      Все остальные методы класса Reporter_abstract осуществляют подготовку параметров и,
         *      в конечном итоге, вызывают данный метод для передачи сообщения.
         *
         * \param level     Степень суровости сообщения
         * \param loc       Позиция
         * \param briefly   Короткая запись сообщения (например, заголовок)
         * \param atlarge   Полная запись сообщения
         */
        virtual void report(const SeverityLevel level,
                            const Location & location,
                            const std::string & briefly,
                            const std::string & atlarge
                            ) = 0;

        /*!
         * \brief Передача сообщения с использованием объекта класса Token в качестве локализатора
         *
         *      В данной реализации локализация определяется по информации в объекте Token.
         *
         *      Метод формирует данные и вызывает интерфейсный метод report.
         *
         * \param level     Степень суровости сообщения
         * \param token     Объект локализации
         * \param briefly   Короткая запись сообщения (например, заголовок)
         * \param atlarge   Полная запись сообщения (не обязательный параметр)
         */
        void    reportWithPosition(const SeverityLevel level,
                       const Location &location,
                       const std::string &briefly,
                       const std::string &atlarge={});

        /*!
         * \brief Передача короткого информационного сообщения без локализации
         *
         *      Метод формирует данные и вызывает интерфейсный метод report.
         *
         * \param briefly   Короткая запись сообщения (например, заголовок)
         */
        void    reportInformation(const std::string &briefly)
        {
            report(SeverityLevel::Information, null_location, briefly, {});
        }

        /*!
         * \brief Передача информационного сообщения с локализацией
         *
         *      В данной реализации локализация определяется по информации в объекте Token.
         *
         *      Метод формирует данные и вызывает интерфейсный метод report.
         *
         * \param token     Объект локализации
         * \param briefly   Короткая запись сообщения (например, заголовок)
         * \param atlarge   Полная запись сообщения (не обязательный параметр)
         */
        void    reportInformation(const Location &location,
                                  const std::string &briefly,
                                  const std::string &atlarge = {})
        {
            reportWithPosition(SeverityLevel::Information, location, briefly, atlarge);
        }

        /*!
         * \brief Передача предупреждения с локализацией
         *
         *      В данной реализации локализация определяется по информации в объекте Token.
         *
         *      Метод формирует данные и вызывает интерфейсный метод report.
         *
         * \param token     Объект локализации
         * \param briefly   Короткая запись сообщения (например, заголовок)
         * \param atlarge   Полная запись сообщения (не обязательный параметр)
         */
        void    reportWarning(const Location &location,
                              const std::string &briefly,
                              const std::string &atlarge = {})
        {
            reportWithPosition(SeverityLevel::Warning, location, briefly, atlarge);
        }

        /*!
         * \brief Передача сообщения об ошибке с локализацией
         *
         *      В данной реализации локализация определяется по информации в объекте Token.
         *
         *      Метод формирует данные и вызывает интерфейсный метод report.
         *
         * \param token     Объект локализации
         * \param briefly   Короткая запись сообщения (например, заголовок)
         * \param atlarge   Полная запись сообщения (не обязательный параметр)
         */
        void    reportError(const Location &location,
                            const std::string &briefly,
                            const std::string &atlarge = {})
        {
            reportWithPosition(SeverityLevel::Error, location, briefly, atlarge);
        }

        /*!
         * \brief Передача короткого фатального сообщения без локализации
         *
         *      Метод формирует данные и вызывает интерфейсный метод report.
         *
         * \param briefly   Короткая запись сообщения (например, заголовок)
         */
        void    reportFatal(const std::string &briefly)
        {
            report(SeverityLevel::Fatal, null_location, briefly, {});
        }

        /*!
         * \brief Передача фатального сообщения с локализацией
         *
         *      В данной реализации локализация определяется по информации в объекте Token.
         *
         *      Метод формирует данные и вызывает интерфейсный метод report.
         *
         * \param token     Объект локализации
         * \param briefly   Короткая запись сообщения (например, заголовок)
         * \param atlarge   Полная запись сообщения (не обязательный параметр)
         */
        void    reportFatal(const Location &location,
                            const std::string &briefly,
                            const std::string &atlarge = {})
        {
            reportWithPosition(SeverityLevel::Fatal, location, briefly, atlarge);
        }
    };

    /*!
     * \brief Реализация пустого отображения сообщений
     *
     *      Класс NullReporter полезен, если все сообщения никак не требуется отображать.
     */
    class NullReporter: public Reporter_abstract
    {
    public:
        virtual void report(const SeverityLevel ,
                            const Location & ,
                            const std::string & ,
                            const std::string & )
        override final
        {}
    };

    /*!
     * \brief Функция получения строкового наименования уровня суровости сообщения
     * \param level     Уровень суровости (тип SeverityLevel)
     * \return          Ссылка на наименование уровня суровости
     */
    const char * getSeverityLevelName(SeverityLevel level);

    /*!
     * \brief Функция получения строки с описанием локации
     * \param token     Объект локализации
     * \param in_detail Признак вывода дополнительной информации.
     *                  Если true, то в скобках выводится позиция начала и конца символа от начала документа
     * \return          Строка с описанием локации
     */
    std::string getLocationString(const Location & location, bool in_detail=true);

}

#endif // simodo_token_Reporter_abstract
